import random
from threading import Thread
from ProtocolDefine import GameDefineProtocol
from GameUtils import CardGame,ChessGame
from collections import deque
import time


class XiangqiGame(ChessGame):
    MAX_USER = 2
    idle_time = None

    def processRequest(self):
        while True:
            try:
                user,request = self.RequestList.pop()
                args = request.strip().split(" ")
                command = args[0]
            except:
                break
            try:
                cmd = GameDefineProtocol().GameCommand()
                if command == cmd.COMMAND_PART:
                    self.pcuserPart(user)                        
                elif command == cmd.COMMAND_START:
                    self.pcstartGame(user)                        
                elif command == cmd.COMMAND_PLAY:
                    movement = ' '.join(args[1:])
                    self.pcuserPlay(user,movement)                        
                elif command == cmd.COMMAND_FINISH:
                    self.pcuserFinish(user)                                                 
            except Exception as err:
                print err
                raise
    
    def processGameEvent(self):
        try:
            if self.status == "playing":
                #check whether game finish
                bdone = True
                for user in self.userlistcurrent:
                    if self.statusPlayingUser[user]==True:
                        bdone = False
                        break
                # if game finished
                if bdone:
                    notify = GameDefineProtocol().GameNotify()
                    self.broadcast(notify.NOTIFY_FINISH_GAME)
                    #broadcast result
                    self.calUserScore()
                    for i in range(len(self.userlistcurrent)):
                        strcard = ""
                        for card in self.usercards[i]:
                            strcard = strcard + str(card)+" "
                        self.broadcast(notify.NOTIFY_USER_CARDS+ " "+self.userlistcurrent[i]+" "+strcard.strip())
                        self.broadcast(notify.NOTIFY_USER_SCORE+ " " +self.userlistcurrent[i]+" "+str(self.userscore[i]))                        
                        
                    #broadcast winner
                    self.calUserMoney()
                    strwin = ""
                    for winner in self.userwinners:
                        strwin = strwin + winner + " "
                    strwin = strwin.strip()
                    self.broadcast(notify.NOTIFY_USER_WIN+ " "+strwin)
                    #update money
                    for i in range(len(self.userlistcurrent)):
                        self.pcuserMoney(self.userlistcurrent[i])
                    #delete all result                    
                    for cards in self.usercards:
                        if cards:
                            del cards[:]
                    del self.userwinners[:]
                    self.status = "waiting"
                    self.broadcast(notify.NOTIFY_GAME_WAITING)                    
                    self.idle_time = time.time()                    
                    print "Game done"
            #start game after 10s
#            if self.status == "waiting":
#                if len(self.userlist)==1:                
#                    self.status = None
#                if time.time() - self.idle_time > 10:
#                    self.pcstartGame(self.host)
        
        except Exception as err:
            print err
            raise

    def deal(self):
        #find player host
        i = self.userlistcurrent.index(self.host)
        self.currentturn = i    

    def pcuserMoney(self,user):
        notify = GameDefineProtocol.GameNotify()
        imoney = self.getUserMoney(user)
        smoney = str(imoney)
        self.addResponse((user,notify.NOTIFY_USER_MONEY+" "+user+" "+smoney))
        
    def pcuserPart(self,user):
        self.pcuserFinish(user)
        self.protocoldict[user].userhandle.partRoom()

    def pcstartGame(self,user=None):
        err = GameDefineProtocol().GameError()
#        if user <> self.host:
#            self.addResponse((user,err.NOTIFY_START_GAME_ERROR))
#            #self.broadcast(err.NOTIFY_START_GAME_ERROR)
#            return
        if (not self.status) or self.status == "waiting":
            if len(self.userlist)>1:
                notify = GameDefineProtocol().GameNotify()
                self.status = "playing"
                self.userlistcurrent = self.userlist[:]
                #self.initdeck()
                for key in self.statusPlayingUser.keys():
                    del self.statusPlayingUser[key]                
                for i in range(len(self.userlistcurrent)):
                    self.statusPlayingUser[self.userlistcurrent[i]]=True
                self.broadcast(notify.NOTIFY_START_GAME)
                self.deal()
                self.broadcast(notify.NOTIFY_USER_TURN+ " " + self.userlistcurrent[self.currentturn])
            else:
                self.broadcast(err.NOTIFY_START_GAME_ERROR)
        else:
            self.broadcast(err.NOTIFY_START_GAME_ERROR)
            
    def pcuserPlay(self,user,movement):
        if self.status == "playing":
            try:
                i = self.userlistcurrent.index(user)
            except:
                i = -1
            if (i<>-1) and (i == self.currentturn):
                notify = GameDefineProtocol().GameNotify()
                self.broadcast(notify.NOTIFY_USER_PLAY + " "+ user+" "+movement)
                if self.currentturn < len(self.userlistcurrent)-1:
                    self.currentturn = i+1
                else:
                    self.currentturn = 0
                self.broadcast(notify.NOTIFY_USER_TURN + " "+ self.userlistcurrent[self.currentturn])
            else:
                return
            
    def pcuserFinish(self,user):
        if self.status == "playing":
            notify = GameDefineProtocol().GameNotify()
            self.statusPlayingUser[user]=False
            self.broadcast(notify.NOTIFY_USER_FINISH+ " " + user)            
            #check all user whether finish ???
            if self.userlistcurrent[self.currentturn] == user:
                bdone = True
                for u in self.userlistcurrent:
                    if self.statusPlayingUser[u]==True:
                        bdone = False
                        break
                #if not finish all, find a next turn
                if not bdone:
                    try:
                        i = self.userlistcurrent.index(user)
                    except:
                        i = -1
                    if i <> -1:
                        inext = -1;
                        for j in range(i,len(self.userlistcurrent)):
                            if self.statusPlayingUser[self.userlistcurrent[j]]== True:
                                inext = j
                                break
                        if inext == -1:
                            for j in range(0,i):
                                if self.statusPlayingUser[self.userlistcurrent[j]] == True:
                                    inext = j
                                    break
                        self.currentturn = inext
                        self.broadcast(notify.NOTIFY_USER_TURN+ " " + self.userlistcurrent[self.currentturn])                        
                        
    def calUserScore(self):
        def getpoint(value):
            r = value / 4
            if value % 4 <> 0: r = r+1
            if r > 10: r = 10
            return r
         
        for i in range(len(self.usercards)):
            if self.usercards[i]:
                if len(self.usercards[i]) == 2:
                    r1 = getpoint(self.usercards[i][0])
                    r2 = getpoint(self.usercards[i][1])
                    if r1 == 1 and r2 == 1:
                        self.userscore[i] = 200
                    else:
                        if r1 == 1 : r1 = 11
                        if r2 == 1 : r2 = 11
                        score = r1 + r2
                        if score == 21:
                            score = 100
                        else:
                            if score<16 : score = 0 
                        self.userscore[i] = score
                elif len(self.usercards[i]) == 3:
                    r1 = getpoint(self.usercards[i][0])
                    r2 = getpoint(self.usercards[i][1])
                    r3 = getpoint(self.usercards[i][2])
                    if r1 == 1 or r2 == 1 or r3 == 1:
                        score = r1 + r2 + r3
                        if score <= 11 :
                            score = score + 10
                    else:
                        score = r1 + r2 + r3
                    if score > 21 or score <16 : score = 0
                    self.userscore[i] = score
                elif len(self.usercards[i])> 3:
                    score = 0
                    for card in self.usercards[i]:
                        score = score + getpoint(card)
                    if score > 21:
                        score = 0
                    else:
                        if len(self.usercards[i]) == 5:
                            score = 50
                        else:
                            if score < 16 : score = 0
                    self.userscore[i] = score                                            
    
    def calUserMoney(self):
        max = 0
        #find a max score
        for score in self.userscore:
            if score > max : max = score
        for i in range(0,len(self.userscore)):
            if self.userscore[i] == max : self.userwinners.append(self.userlistcurrent[i])
    
    def broadcast(self,data):
        try:
            for user in self.userlist:
                self.addResponse((user,data))
        except:
            pass
    

class AGame(CardGame): #xi la'c
    
    MAX_USER = 10
    idle_time = None
                                
    def processRequest(self):
        while True:
            try:
                user,request = self.RequestList.pop()
                args = request.strip().split(" ")
                command = args[0]
            except:
                break
            try:
                cmd = GameDefineProtocol().GameCommand()
                if command == cmd.COMMAND_PART:
                    self.pcuserPart(user)                        
                elif command == cmd.COMMAND_START:
                    self.pcstartGame(user)                        
#                elif command == cmd.COMMAND_READY:
#                    self.pcuserReady(user)                        
                elif command == cmd.COMMAND_PLAY:
                    self.pcuserPlay(user)                        
                elif command == cmd.COMMAND_FINISH:
                    self.pcuserFinish(user)                                                 
            except Exception as err:
                print err
                raise
    
    def processGameEvent(self):
        try:
            if self.status == "playing":
                #check whether game finish
                bdone = True
                for user in self.userlistcurrent:
                    if self.statusPlayingUser[user]==True:
                        bdone = False
                        break
                # if game finished
                if bdone:
                    notify = GameDefineProtocol().GameNotify()
                    self.broadcast(notify.NOTIFY_FINISH_GAME)
                    #broadcast result
                    self.calUserScore()
                    for i in range(len(self.userlistcurrent)):
                        strcard = ""
                        for card in self.usercards[i]:
                            strcard = strcard + str(card)+" "
                        self.broadcast(notify.NOTIFY_USER_CARDS+ " "+self.userlistcurrent[i]+" "+strcard.strip())
                        self.broadcast(notify.NOTIFY_USER_SCORE+ " " +self.userlistcurrent[i]+" "+str(self.userscore[i]))                        
                        
                    #broadcast winner
                    self.calUserMoney()
                    strwin = ""
                    for winner in self.userwinners:
                        strwin = strwin + winner + " "
                    strwin = strwin.strip()
                    self.broadcast(notify.NOTIFY_USER_WIN+ " "+strwin)
                    #update money
                    for i in range(len(self.userlistcurrent)):
                        self.pcuserMoney(self.userlistcurrent[i])
                    #delete all result                    
                    for cards in self.usercards:
                        if cards:
                            del cards[:]
                    del self.userwinners[:]
                    self.status = "waiting"
                    self.broadcast(notify.NOTIFY_GAME_WAITING)                    
                    self.idle_time = time.time()                    
                    print "Game done"
            #start game after 10s
            if self.status == "waiting":
                if len(self.userlist)==1:                
                    self.status = None
                if time.time() - self.idle_time > 10:
                    self.pcstartGame(self.host)
        
        except Exception as err:
            print err
            raise

    def deal(self):
        for c in range(0,2):#a user has 2 cards
            for i in range(0,len(self.userlistcurrent)):
                if not self.usercards[i]:
                    self.usercards[i] = [self.deck[0],]
                else:
                    self.usercards[i].append(self.deck[0])
                del self.deck[0]
        notify = GameDefineProtocol().GameNotify()
        for i in range(len(self.userlistcurrent)):
#            self.protocoldict[self.userlistcurrent[i]].response(str(self.usercards[i]))
            strcard = ""
            for card in self.usercards[i]:
                strcard = strcard + str(card)+" "
            self.addResponse((self.userlistcurrent[i],(notify.NOTIFY_USER_CARDS+ " "+self.userlistcurrent[i]+" "+strcard.strip())))
        #find player next to host
        i = self.userlistcurrent.index(self.host)
        if (i<len(self.userlistcurrent)-1):
            self.currentturn = i+1
        else:
            self.currentturn = 0    

    def pcuserMoney(self,user):
        notify = GameDefineProtocol.GameNotify()
        imoney = self.getUserMoney(user)
        smoney = str(imoney)
        self.addResponse((user,notify.NOTIFY_USER_MONEY+" "+user+" "+smoney))
        
    def pcuserPart(self,user):
        self.pcuserFinish(user)
        self.protocoldict[user].userhandle.partRoom()

    def pcstartGame(self,user):
        err = GameDefineProtocol().GameError()
        if user <> self.host:
            self.addResponse((user,err.NOTIFY_START_GAME_ERROR))
            #self.broadcast(err.NOTIFY_START_GAME_ERROR)
            return
        if (not self.status) or self.status == "waiting":
            if len(self.userlist)>1:
                notify = GameDefineProtocol().GameNotify()
                self.status = "playing"
                self.userlistcurrent = self.userlist[:]
                self.initdeck()
                for key in self.statusPlayingUser.keys():
                    del self.statusPlayingUser[key]                
                for i in range(len(self.userlistcurrent)):
                    self.statusPlayingUser[self.userlistcurrent[i]]=True
                self.broadcast(notify.NOTIFY_START_GAME)
                self.deal()
                self.broadcast(notify.NOTIFY_USER_TURN+ " " + self.userlistcurrent[self.currentturn])
            else:
                self.broadcast(err.NOTIFY_START_GAME_ERROR)
        else:
            self.broadcast(err.NOTIFY_START_GAME_ERROR)
            
    def pcuserPlay(self,user):
        if self.status == "playing":
            try:
                i = self.userlistcurrent.index(user)
            except:
                i = -1
            if (i<>-1) and (i == self.currentturn):
                notify = GameDefineProtocol().GameNotify()
                if len(self.usercards[i])<5:
                    self.usercards[i].append(self.deck[0])
                    del self.deck[0]
                    self.broadcast(notify.NOTIFY_USER_PLAY + " "+ user)
                else:                
                    return
                strcard = ""
                for card in self.usercards[i]:
                    strcard = strcard + str(card)+" "            
                self.addResponse((user,notify.NOTIFY_USER_CARDS+ " "+ user+ " " + strcard.strip()))                
                if len(self.usercards[i])==5:
                    self.pcuserFinish(user)                    
            else:
                return
            
    def pcuserFinish(self,user):
        if self.status == "playing":
            notify = GameDefineProtocol().GameNotify()
            self.statusPlayingUser[user]=False
            self.broadcast(notify.NOTIFY_USER_FINISH+ " " + user)            
            #check all user whether finish ???
            if self.userlistcurrent[self.currentturn] == user:
                bdone = True
                for u in self.userlistcurrent:
                    if self.statusPlayingUser[u]==True:
                        bdone = False
                        break
                #if not finish all, find a next turn
                if not bdone:
                    try:
                        i = self.userlistcurrent.index(user)
                    except:
                        i = -1
                    if i <> -1:
                        inext = -1;
                        for j in range(i,len(self.userlistcurrent)):
                            if self.statusPlayingUser[self.userlistcurrent[j]]== True:
                                inext = j
                                break
                        if inext == -1:
                            for j in range(0,i):
                                if self.statusPlayingUser[self.userlistcurrent[j]] == True:
                                    inext = j
                                    break
                        self.currentturn = inext
                        self.broadcast(notify.NOTIFY_USER_TURN+ " " + self.userlistcurrent[self.currentturn])                        
                        
    def calUserScore(self):
        def getpoint(value):
            r = value / 4
            if value % 4 <> 0: r = r+1
            if r > 10: r = 10
            return r
         
        for i in range(len(self.usercards)):
            if self.usercards[i]:
                if len(self.usercards[i]) == 2:
                    r1 = getpoint(self.usercards[i][0])
                    r2 = getpoint(self.usercards[i][1])
                    if r1 == 1 and r2 == 1:
                        self.userscore[i] = 200
                    else:
                        if r1 == 1 : r1 = 11
                        if r2 == 1 : r2 = 11
                        score = r1 + r2
                        if score == 21:
                            score = 100
                        else:
                            if score<16 : score = 0 
                        self.userscore[i] = score
                elif len(self.usercards[i]) == 3:
                    r1 = getpoint(self.usercards[i][0])
                    r2 = getpoint(self.usercards[i][1])
                    r3 = getpoint(self.usercards[i][2])
                    if r1 == 1 or r2 == 1 or r3 == 1:
                        score = r1 + r2 + r3
                        if score <= 11 :
                            score = score + 10
                    else:
                        score = r1 + r2 + r3
                    if score > 21 or score <16 : score = 0
                    self.userscore[i] = score
                elif len(self.usercards[i])> 3:
                    score = 0
                    for card in self.usercards[i]:
                        score = score + getpoint(card)
                    if score > 21:
                        score = 0
                    else:
                        if len(self.usercards[i]) == 5:
                            score = 50
                        else:
                            if score < 16 : score = 0
                    self.userscore[i] = score                                            
    
    def calUserMoney(self):
        max = 0
        #find a max score
        for score in self.userscore:
            if score > max : max = score
        for i in range(0,len(self.userscore)):
            if self.userscore[i] == max : self.userwinners.append(self.userlistcurrent[i])
    
    def broadcast(self,data):
        try:
            for user in self.userlist:
                self.addResponse((user,data))
        except:
            pass
       
class TienLenGame(CardGame): #tien len
    
    MAX_USER = 4
    idle_time = None
    statusPass = dict()
    NOT_START = True
                                
    def processRequest(self):
        while True:
            try:
                user,request = self.RequestList.pop()
                args = request.strip().split(" ")
                command = args[0]
            except:
                break
            try:
                cmd = GameDefineProtocol().GameCommand()
                if command == cmd.COMMAND_PART:
                    self.pcuserPart(user)                        
                elif command == cmd.COMMAND_START:
                    self.pcstartGame(user)                        
#                elif command == cmd.COMMAND_READY:
#                    self.pcuserReady(user)                        
                elif command == cmd.COMMAND_PLAY:
                    if len(args)>=2:
                        cardlist = args[1:]
                        icardlist = []
                        for card in cardlist:
                            icardlist.append(int(card))
                        self.pcuserPlay(user,icardlist)
                    else:
                        self.pcuserPass(user)                        
                elif command == cmd.COMMAND_FINISH:
                    self.pcuserFinish(user)                                                 
            except Exception as err:
                print err
                raise
    
    def processGameEvent(self):
        try:
            if self.status == "playing":
                #check whether game finish
                bdone = False
                bcount = 0
                #how many user has finished
                for user in self.userlistcurrent:
                    if self.statusPlayingUser[user]==False:
                        bcount +=1
                #if there are len-1 finished user, game done
                if bcount >= len(self.userlistcurrent)-1:
                    bdone = True
                # if game finished
                if bdone:
                    notify = GameDefineProtocol().GameNotify()
                    self.broadcast(notify.NOTIFY_FINISH_GAME)
                    #broadcast result
                    #broadcast winner                    
                    for user in self.userlistcurrent:
                        if user not in self.userscore:
                            self.userscore.append(user)
                    strwin = ""
                    for winner in self.userscore:
                        strwin = strwin + winner + " "
                    strwin = strwin.strip()
                    self.broadcast(notify.NOTIFY_USER_WIN+ " "+strwin)
                    #update money
                    for i in range(len(self.userlistcurrent)):
                        self.pcuserMoney(self.userlistcurrent[i])
                    #delete all result                    
                    for cards in self.usercards:
                        if cards:
                            del cards[:]
                    del self.userwinners[:]                    
                    self.status = "waiting"
                    self.broadcast(notify.NOTIFY_GAME_WAITING)                    
                    self.idle_time = time.time()                    
                    print "Game done"
            #start game after 10s
#            if self.status == "waiting":
#                if len(self.userlist)==1:                
#                    self.status = None
#                if time.time() - self.idle_time > 10:
#                    self.pcstartGame(self.host)
        
        except Exception as err:
            print err
            raise

    def deal(self):
        for c in range(0,2):#a user has 13 cards
            for i in range(0,len(self.userlistcurrent)):
                if not self.usercards[i]:
                    self.usercards[i] = [self.deck[0],]
                else:
                    self.usercards[i].append(self.deck[0])
                del self.deck[0]
        notify = GameDefineProtocol().GameNotify()
        for i in range(len(self.userlistcurrent)):
#            self.protocoldict[self.userlistcurrent[i]].response(str(self.usercards[i]))
            strcard = ""
            for card in self.usercards[i]:
                strcard = strcard + str(card)+" "
            self.addResponse((self.userlistcurrent[i],(notify.NOTIFY_USER_CARDS+ " "+self.userlistcurrent[i]+" "+strcard.strip())))

    def pcuserMoney(self,user):
        notify = GameDefineProtocol.GameNotify()
        imoney = self.getUserMoney(user)
        smoney = str(imoney)
        self.addResponse((user,notify.NOTIFY_USER_MONEY+" "+user+" "+smoney))
        
    def pcuserPart(self,user):
        self.pcuserFinish(user)
        self.protocoldict[user].userhandle.partRoom()

    def findfirstturn(self):
        try:
            if self.NOT_START:                
                i = self.userlistcurrent.index(self.host)
                return i
            else:
                for i in range(0,len(self.userscore)):
                    if self.userscore[i] in self.userlist:
                        return i
        except:
            pass
        return 0    
                
    def pcstartGame(self,user):
        err = GameDefineProtocol().GameError()
        self.lastplay = None
        self.lastuser = None
        if user <> self.host:
            self.addResponse((user,err.NOTIFY_START_GAME_ERROR))
            #self.broadcast(err.NOTIFY_START_GAME_ERROR)
            return
        if (not self.status) or self.status == "waiting":
            if len(self.userlist)>1:
                #find to host
                notify = GameDefineProtocol().GameNotify()
                self.status = "playing"
                self.userlistcurrent = self.userlist[:]
                #first turn is host
                self.currentturn = self.findfirstturn()
                #init deck                    
                self.initdeck()
                del self.userscore[:]
                for key in self.statusPlayingUser.keys():
                    del self.statusPlayingUser[key]
                for key in self.statusPass.keys():
                    del self.statusPass[key]                                                
                for i in range(len(self.userlistcurrent)):
                    self.statusPlayingUser[self.userlistcurrent[i]]=True
                for i in range(len(self.userlistcurrent)):
                    self.statusPass[self.userlistcurrent[i]]=False
                self.broadcast(notify.NOTIFY_START_GAME)
                self.deal()
                self.broadcast(notify.NOTIFY_USER_TURN+ " " + self.userlistcurrent[self.currentturn])
                self.NOT_START = False
                #del self.userscore[:]
            else:
                self.broadcast(err.NOTIFY_START_GAME_ERROR)
        else:
            self.broadcast(err.NOTIFY_START_GAME_ERROR)
            
    def pcuserPass(self,user):
        notify = GameDefineProtocol().GameNotify()
        if self.status == "playing":
            try:
                i = self.userlistcurrent.index(user)
            except:
                i = -1
            #if user is valid
            if i <> -1 and i == self.currentturn:
                inext = self.findnextuser()
                #change turn
                if inext <> -1 :
                    self.broadcast(notify.NOTIFY_USER_PLAY+" "+user)
                    self.statusPass[user] = True                    
                    self.currentturn = inext
                    self.broadcast(notify.NOTIFY_USER_TURN+ " " + self.userlistcurrent[self.currentturn])
                    
                    countpass = 0
                    for user in self.userlistcurrent:
                        if self.statusPass[user]==True:
                            countpass+=1
                    #if there are len-1 user has passed                    
                    if countpass >= len(self.userlistcurrent)-1:
                        #end a round
                        self.lastplay = None
                        for user in self.userlistcurrent:
                            self.statusPass[user]=False

    def getpoint(self,value):
        r = value / 4
        if value % 4 <> 0: r = r+1        
        return r

    def validCard(self,user,cardlist):
        
        def getTienLenValue(card):
            if card in range(1,9):
                return 52+card
            else:
                return card
        
        def Pair(list):
            if len(list)==2:
                if self.getpoint(list[0]) == self.getpoint(list[1]):
                    return True
            return False
                    
        def Three_of_a_kind(list):
            if len(list)==3:
                if self.getpoint(list[0]) == self.getpoint(list[1]) == self.getpoint(list[2]):
                    return True
            return False
        
        def Straight(list):
            if len(list)<3: return False
            cardpoint = []
            for card in list:
                #there is no 2 in a Straight
                if card in range(5,9):
                    return False
                cardpoint.append(self.getpoint(getTienLenValue(card)))
            cardpoint.sort()
            for i in range(0,len(cardpoint)-2):
                if cardpoint[i+1] - cardpoint[i] <> 1:
                    return False
            return True
        
        def Four_of_a_kind(list):
            if len(list)==4:
                if self.getpoint(list[0]) == self.getpoint(list[1]) == \
                self.getpoint(list[2]) == self.getpoint(list[3]):
                    return True
            return False
        
        def Double_3_Straight(list):
            slen = 3
            if len(list)==slen*2:
                cardpoint = []
                for card in list:
                    if card in range(5,9):
                        return False
                    cardpoint.append(self.getpoint(getTienLenValue(card)))
                cardpoint.sort()
                for i in range(0,slen):
                    if cardpoint[i*2]<>cardpoint[i*2+1]:
                        return False
                for i in range(1,slen):
                    if cardpoint[i*2] - cardpoint[i*2-1]<>1:
                        return False
            else:
                return False
            return True

        def Double_4_Straight(list):
            slen = 4
            if len(list)==slen*2:
                cardpoint = []
                for card in list:
                    if card in range(5,9):
                        return False
                    cardpoint.append(self.getpoint(getTienLenValue(card)))
                cardpoint.sort()
                for i in range(0,slen):
                    if cardpoint[i*2]<>cardpoint[i*2+1]:
                        return False
                for i in range(1,slen):
                    if cardpoint[i*2] - cardpoint[i*2-1]<>1:
                        return False
            else:
                return False
            return True

        def Double_5_Straight(list):
            slen = 5
            if len(list)==slen*2:
                cardpoint = []
                for card in list:
                    if card in range(5,9):
                        return False
                    cardpoint.append(self.getpoint(getTienLenValue(card)))
                cardpoint.sort()
                for i in range(0,slen):
                    if cardpoint[i*2]<>cardpoint[i*2+1]:
                        return False
                for i in range(1,slen):
                    if cardpoint[i*2] - cardpoint[i*2-1]<>1:
                        return False
            else:
                return False
            return True
        
        #check whether user has these cards
        i = -1
        try:
            i = self.userlistcurrent.index(user)
        except:
            i = -1
        if i <> -1:
            for card in cardlist:
                if card not in self.usercards[i]:
                    print card, 'not in ', self.usercards[i]
                    return False
        else:
            return False
        
        if len(cardlist)==1:
            if self.lastplay:
                if len(self.lastplay)==1:
                    if getTienLenValue(self.lastplay[0]) < getTienLenValue(cardlist[0]):
                        return True
                    else:
                        return False
                else:
                    return False
            else:            
                return True
        elif len(cardlist)==2:
            if Pair(cardlist):
                if self.lastplay:
                    if Pair(self.lastplay):
                        if getTienLenValue(max(self.lastplay)) < getTienLenValue(max(cardlist)):
                            return True
                        else:
                            return False
                    else:
                        return False
                else:    
                    return True
        elif len(cardlist)==3:
            if Three_of_a_kind(cardlist):
                if self.lastplay:
                    if Three_of_a_kind(self.lastplay):
                        if getTienLenValue(max(self.lastplay)) < getTienLenValue(max(cardlist)):
                            return True
                        else:
                            return False
                    else:
                        return False
                else:
                    return True
            if Straight(cardlist):
                if self.lastplay:
                    if Straight(self.lastplay):
                        if getTienLenValue(max(self.lastplay)) < getTienLenValue(max(cardlist)):
                            return True
                        else:
                            return False
                    else:
                        return False
                else:                    
                    return True
        elif len(cardlist)>3:
            if Straight(cardlist):
                if self.lastplay:
                    if Straight(self.lastplay):
                        if getTienLenValue(max(self.lastplay)) < getTienLenValue(max(cardlist))\
                        and len(self.lastplay) == len(cardlist):
                            return True
                        else:
                            return False
                    else:
                        return False
                else:                    
                    return True
            if Four_of_a_kind(cardlist):
                if self.lastplay:
                    pass
                else:
                    return True
            if Double_3_Straight(cardlist):
                if self.lastplay:
                    pass
                else:
                    return True            
            if Double_4_Straight(cardlist):
                if self.lastplay:
                    pass
                else:
                    return True                                        
        return False
    
    def findnextuser(self):
        i = self.currentturn + 1
        inext = -1;
        for j in range(i,len(self.userlistcurrent)):
            if self.statusPlayingUser[self.userlistcurrent[j]]== True \
            and self.statusPass[self.userlistcurrent[j]]==False:
                inext = j
                break
        if inext == -1:
            for j in range(0,i):
                if self.statusPlayingUser[self.userlistcurrent[j]] == True \
                and self.statusPass[self.userlistcurrent[j]]==False:
                    inext = j
                    break
        return inext        
    
    def pcuserPlay(self,user,cardlist):
        notify = GameDefineProtocol().GameNotify()
        if self.status == "playing":
            if self.validCard(user,cardlist):
                try:
                    i = self.userlistcurrent.index(user)
                except:
                    i = -1
                #move cards
                if i <> -1 and i == self.currentturn:
                    strcard = ""
                    for card in cardlist:
                        self.usercards[i].remove(card)
                        strcard = strcard + str(card)+ " "
                    self.broadcast(notify.NOTIFY_USER_PLAY+" "+user+" "+strcard.strip())
                    strcard = ""
                    for card in self.usercards[i]:
                        strcard = strcard + str(card) + " "
                    self.addResponse((user,notify.NOTIFY_USER_CARDS+" "+user+" "+strcard.strip()))
                    #if user play all card, he will finish
                    if len(self.usercards[i]) == 0:
                        self.statusPlayingUser[user] = False
                        self.broadcast(notify.NOTIFY_USER_FINISH+" "+user)
                        self.userscore.append(user)
                else:
                    return  
                #save last cards              
                self.lastplay = cardlist[:]
                #save last user
                self.lastuser = user                
                #find next user
                inext = self.findnextuser()
                #change turn
                if inext <> -1 :
                    self.currentturn = inext
                    self.broadcast(notify.NOTIFY_USER_TURN+ " " + self.userlistcurrent[self.currentturn])                                                        
        else:
            return
            
    def pcuserFinish(self,user):
        if self.status == "playing":
            notify = GameDefineProtocol().GameNotify()
            self.statusPlayingUser[user]=False
            self.broadcast(notify.NOTIFY_USER_FINISH+ " " + user)            
            #check all user whether finish ???
            if self.userlistcurrent[self.currentturn] == user:
                bdone = True
                for u in self.userlistcurrent:
                    if self.statusPlayingUser[u]==True:
                        bdone = False
                        break
                #if not finish all, find a next turn
                if not bdone:
                    try:
                        i = self.userlistcurrent.index(user)
                    except:
                        i = -1
                    if i <> -1:
                        inext = -1;
                        for j in range(i,len(self.userlistcurrent)):
                            if self.statusPlayingUser[self.userlistcurrent[j]]== True:
                                inext = j
                                break
                        if inext == -1:
                            for j in range(0,i):
                                if self.statusPlayingUser[self.userlistcurrent[j]] == True:
                                    inext = j
                                    break
                        self.currentturn = inext
                        self.broadcast(notify.NOTIFY_USER_TURN+ " " + self.userlistcurrent[self.currentturn])                        
                        
    def calUserScore(self):
        def getpoint(value):
            r = value / 4
            if value % 4 <> 0: r = r+1
            if r > 10: r = 10
            return r
         
        for i in range(len(self.usercards)):
            if self.usercards[i]:
                if len(self.usercards[i]) == 2:
                    r1 = getpoint(self.usercards[i][0])
                    r2 = getpoint(self.usercards[i][1])
                    if r1 == 1 and r2 == 1:
                        self.userscore[i] = 200
                    else:
                        if r1 == 1 : r1 = 11
                        if r2 == 1 : r2 = 11
                        score = r1 + r2
                        if score == 21:
                            score = 100
                        else:
                            if score<16 : score = 0 
                        self.userscore[i] = score
                elif len(self.usercards[i]) == 3:
                    r1 = getpoint(self.usercards[i][0])
                    r2 = getpoint(self.usercards[i][1])
                    r3 = getpoint(self.usercards[i][2])
                    if r1 == 1 or r2 == 1 or r3 == 1:
                        score = r1 + r2 + r3
                        if score <= 11 :
                            score = score + 10
                    else:
                        score = r1 + r2 + r3
                    if score > 21 or score <16 : score = 0
                    self.userscore[i] = score
                elif len(self.usercards[i])> 3:
                    score = 0
                    for card in self.usercards[i]:
                        score = score + getpoint(card)
                    if score > 21:
                        score = 0
                    else:
                        if len(self.usercards[i]) == 5:
                            score = 50
                        else:
                            if score < 16 : score = 0
                    self.userscore[i] = score                                            
    
    def calUserMoney(self):
        max = 0
        #find a max score
        for score in self.userscore:
            if score > max : max = score
        for i in range(0,len(self.userscore)):
            if self.userscore[i] == max : self.userwinners.append(self.userlistcurrent[i])
    
    def broadcast(self,data):
        try:
            for user in self.userlist:
                self.addResponse((user,data))
        except:
            pass
    
  
    
class PlayerCardGame():
    def __init__(self,protocol):
        self.authenticated = False
        self.username = None
        self.userstatus = None
        self.currentroom = None
        self.protocol = protocol
        self.factory = protocol.factory

    def processData(self,data):
        args = data.strip().split(" ")
        cmd = GameDefineProtocol().GameCommand()
        err = GameDefineProtocol().GameError()
        try:
            #unauthenticated command
            if args[0] == cmd.COMMAND_LOGIN:
                if self.authenticated:
                    self.response(err.NOTIFY_LOGIN_ERROR)
                    return
                username = args[1]
                password = args[2]
                if self.authenticateUser(username, password):
                    bok = self.protocol.factory.addUser(username)
                    if bok:
                        self.authenticated = True
                        self.username = username
                        res = GameDefineProtocol().GameNotify()
                        self.response(res.NOTIFY_LOGIN_OK)
                        self.notifyUserMoney(username)
                    else:
                        self.authenticated = False                        
                        self.response(err.NOTIFY_LOGIN_ERROR)
                return
            elif args[0] == cmd.COMMAND_DEBUG:
                self.factory.debug()
                return
            elif args[0] == cmd.COMMAND_QUIT:
                self.response("Bye bye.")
                self.protocol.transport.loseConnection()
                return                
            
            if self.authenticated:
                #command use only when you are not in any room
                if not self.userstatus:
                    if args[0] == cmd.COMMAND_CREATE_ROOM:
                        if len(args) == 2:
                            betmoney = args[1] 
                            self.createRoom(betmoney=betmoney)
                        elif len(args) == 3:
                            betmoney = args[1]
                            password = args[2]
                            self.createRoom(betmoney=betmoney, password=password)
                        else:
                            self.response(err.NOTIFY_CREATE_ERROR)
                        return
                    elif args[0] == cmd.COMMAND_JOIN:
                        if len(args) == 2:
                            roomname = args[1]
                            self.joinRoom(roomname)
                        elif len(args) == 3:
                            roomname = args[1]
                            password = args[2]
                            self.joinRoom(roomname,password)
                        return
                    elif args[0] == cmd.COMMAND_GET_ROOM_LIST:
                        self.listRoom()
                        return
                #command use only when you are in some room
                elif self.userstatus:
                    self.factory.addGameRequest((self.username,data))
                    return
                #all purpose command
                if args[0] == cmd.COMMAND_ECHO: #test only
                    self.transport.write(data)
                    return
                else:
                    self.response("Unknown command "+args[0])
                    self.protocol.transport.loseConnection()
                    return
            #you can send command only you are authenticated                 
            else:
                self.response("Your are not authenticated.")                
                self.protocol.transport.loseConnection()
                return                
        except Exception as ex:
            print "Error: ",ex
            raise         
    def response(self,data):
        self.protocol.response(data)
    
    def authenticateUser(self,username,password):        
        return True
    
    def getMoney(self,username):
        return 100000
    
    def notifyUserMoney(self,username):
        notify = GameDefineProtocol.GameNotify()
        money = self.getMoney(username)        
        self.response(notify.NOTIFY_USER_MONEY+" "+username+" "+str(money))
    
    def createRoom(self,betmoney,password=None):
        res = GameDefineProtocol().GameNotify()
        err = GameDefineProtocol().GameError()
        bok = self.factory.createRoom(user=self.username,protocol=self.protocol,betmoney=betmoney,password=password)
        if bok:
            #self.response(res.NOTIFY_CREATE_OK)
            self.userstatus = "hosting"
            self.currentroom = self.username
        else:
            self.response(err.NOTIFY_CREATE_ERROR)

    def partRoom(self):
        res = GameDefineProtocol().GameNotify()
        self.factory.partRoom(self.username)
        self.response(res.NOTIFY_PART_OK)
        self.currentroom = None
        self.userstatus = None                
    
    def joinRoom(self,roomname,password=None):
        res = GameDefineProtocol().GameNotify()
        bok = self.factory.joinRoom(user=self.username,hostname=roomname,protocol=self.protocol,password=password)
        if not bok:
            err = GameDefineProtocol().GameError()
            self.response(err.NOTIFY_JOIN_ERROR)
        else:
            #self.response(res.NOTIFY_JOIN_OK)        
            self.userstatus = "joining"
            self.currentroom = roomname
    
    def listRoom(self):
        self.factory.listRoom(self.protocol)
        
    def startGame(self):
        if self.userstatus == "hosting":
            self.factory.startRoom(self.username)
            